#include "DeviceMouseInput.h"

DeviceMouseInput::DeviceMouseInput():
_mouse(),
_hWnd(nullptr){}
DeviceMouseInput::~DeviceMouseInput(){}

void DeviceMouseInput::MouseInit()
{
	HDC glDc = wglGetCurrentDC();
	_hWnd = WindowFromDC(glDc);
	HINSTANCE hInst = GetModuleHandle(NULL);

	//LPDIRECTINPUT8 _lpDI;
	//LPDIRECTINPUTDEVICE8 _lpDIDevice;
	DIDEVICEINSTANCE di;

	_mouse.hwnd = _hWnd;
	_mouse.dinp = NULL;
	_mouse.idev = NULL;

	if (FAILED(DirectInput8Create(hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&_mouse.dinp, NULL)))
	{
		std::cout << "failed create input" << std::endl;
	}

	if (FAILED(_mouse.dinp->CreateDevice(GUID_SysMouse, &_mouse.idev, NULL)))
	{
		std::cout << "failed create device" << std::endl;
	}

	if (FAILED(_mouse.idev->SetDataFormat(&c_dfDIMouse)))
	{
		std::cout << "failed create dataformat" << std::endl;
	}

	if (FAILED(_mouse.idev->SetCooperativeLevel(_hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)))
	{
		std::cout << "failed set cooperative level" << std::endl;
	}

	di.dwSize = sizeof(di);
	if (FAILED(_mouse.idev->GetDeviceInfo(&di)))

		if (_mouse.idev) _mouse.idev->Acquire();

	_mouse.ox = 0;
	_mouse.oy = 0;
	_mouse.oz = 0;
	_mouse.px = 0;
	_mouse.py = 0;
	_mouse.pz = 0;
	_mouse.newbtn = (EMouseState)0;
	_mouse.oldbtn = (EMouseState)0;
	_mouse.clip.left = 0;
	_mouse.clip.right = 640 - 1;
	_mouse.clip.top = 0;
	_mouse.clip.bottom = 480 - 1;
	_mouse.ratio = 1.0;
}

void DeviceMouseInput::MouseUpdate()
{
	if (!_mouse.idev)
		return;

	_mouse.oldbtn = _mouse.newbtn;

	HRESULT hr;
	DIMOUSESTATE im;
	hr = _mouse.idev->GetDeviceState(sizeof(im), &im);
	if (hr == DI_OK)
	{
		_mouse.ox = im.lX;
		_mouse.oy = im.lY;
		_mouse.oz = im.lZ;

		_mouse.newbtn = (EMouseState)0;
		if ((im.rgbButtons[0] & 0x80) != 0)
			_mouse.newbtn |= MOUSE_BUTTON_1;

		if ((im.rgbButtons[1] & 0x80) != 0)
			_mouse.newbtn |= MOUSE_BUTTON_2;

		if ((im.rgbButtons[2] & 0x80) != 0)
			_mouse.newbtn |= MOUSE_BUTTON_3;

		if ((im.rgbButtons[3] & 0x80) != 0)
			_mouse.newbtn |= MOUSE_BUTTON_4;
	}
	else
	{
		_mouse.ox = 0;
		_mouse.oy = 0;
		_mouse.oz = 0;
		_mouse.newbtn = 0;

		if ((hr == DIERR_INPUTLOST)
			|| hr == DIERR_NOTACQUIRED)
		{
			if (_mouse.idev) _mouse.idev->Acquire();
		}
	}

	_mouse.px += (_mouse.ox * _mouse.ratio);
	_mouse.py += (_mouse.oy * _mouse.ratio);
	_mouse.pz += (_mouse.oz * _mouse.ratio);

	if (_mouse.px < _mouse.clip.left)
		_mouse.px = (float)_mouse.clip.left;
	else if (_mouse.px > _mouse.clip.right)
		_mouse.px = (float)_mouse.clip.right;

	if (_mouse.py < _mouse.clip.top)
		_mouse.py = (float)_mouse.clip.top;
	else if (_mouse.py > _mouse.clip.bottom)
		_mouse.py = (float)_mouse.clip.bottom;
}

void DeviceMouseInput::MouseFinish()
{
	if (_mouse.idev != NULL)
	{
		_mouse.idev->Unacquire();
		_mouse.idev->Release();
		_mouse.idev = NULL;
	}

	if (_mouse.dinp != NULL)
	{
		_mouse.dinp->Release();
		_mouse.dinp = NULL;
	}
}

void DeviceMouseInput::MouseActiveInput()
{
	if (_mouse.idev) _mouse.idev->Acquire();
}

void DeviceMouseInput::GetMouseOffsetPosition(int* x, int* y, int* z)
{
	Mouse* mouse = &_mouse;

	if (x != NULL)
	{
		*x = (int)mouse->ox;
	}
	if (y != NULL)
	{
		*y = (int)mouse->oy;
	}
	if (z != NULL)
	{
		*z = (int)mouse->oz;
	}
}

void DeviceMouseInput::GetMouseCursorPosition(int* x, int* y)
{
	Mouse* mouse = &_mouse;

	if (x != NULL) *x = (int)mouse->px;

	if (y != NULL) *y = (int)mouse->py;
}

bool DeviceMouseInput::GetMouseButtonState(EMouseState state)
{
	Mouse* mouse = &_mouse;

	if ((mouse->newbtn & state) != 0)
		return true;

	return false;
}

bool DeviceMouseInput::GetMouseButtonTrigger(EMouseState state)
{
	Mouse* mouse = &_mouse;

	if (((~mouse->oldbtn & mouse->newbtn) & state) != 0)
		return true;

	return false;
}

bool DeviceMouseInput::GetMouseButtonDetach(EMouseState state)
{
	Mouse* mouse = &_mouse;

	if (((mouse->oldbtn & ~mouse->newbtn) & state) != 0)
		return true;

	return false;
}

float DeviceMouseInput::GetMouseMoveRatio()
{
	Mouse* mouse = &_mouse;

	return mouse->ratio;
}

void DeviceMouseInput::GetMousePhysicalBlock(int* xMin, int* xMax, int* yMin, int* yMax)
{
	if (xMin != NULL)
		*xMin = _mouse.clip.left;

	if (xMax != NULL)
		*xMax = _mouse.clip.right;

	if (yMin != NULL)
		*yMin = _mouse.clip.top;

	if (yMax != NULL)
		*yMax = _mouse.clip.bottom;
}

void DeviceMouseInput::SetMousePhysicalBlock(int xMin, int xMax, int yMin, int yMax)
{
	_mouse.clip.left	= xMin;
	_mouse.clip.right	= xMax;
	_mouse.clip.top		= yMin;
	_mouse.clip.bottom	= yMax;
}

void DeviceMouseInput::SetMouseCursorPosition(int x, int y)
{
	_mouse.px = (float)x;
	_mouse.py = (float)y;

	if (_mouse.px < _mouse.clip.left)
		_mouse.px = (float)_mouse.clip.left;
	else if (_mouse.px > _mouse.clip.right)
		_mouse.px = (float)_mouse.clip.right;

	if (_mouse.py < _mouse.clip.top)
		_mouse.py = (float)_mouse.clip.top;
	else if (_mouse.py > _mouse.clip.bottom)
		_mouse.py = (float)_mouse.clip.bottom;
}

void DeviceMouseInput::SetMouseMoveRatio(float ratio)
{
	_mouse.ratio = ratio;
}

void DeviceMouseInput::GetMouseWindowSpaceCursorPosition(int* x, int* y)
{
	GetMouseScreenSpaceCursorPosition(x, y);

	POINT lPoint;
	lPoint.x = *x;
	lPoint.y = *y;

	ScreenToClient(_mouse.hwnd, &lPoint);

	*x = lPoint.x;
	*y = lPoint.y;

	_mouse.px = (float)(*x);
	_mouse.py = (float)(*y);

	if (_mouse.px < _mouse.clip.left)
		_mouse.px = (float)_mouse.clip.left;
	else if (_mouse.px > _mouse.clip.right)
		_mouse.px = (float)_mouse.clip.right;

	if (_mouse.py < _mouse.clip.top)
		_mouse.py = (float)_mouse.clip.top;
	else if (_mouse.py > _mouse.clip.bottom)
		_mouse.py = (float)_mouse.clip.bottom;

	*x = (int)_mouse.px;
	*y = (int)_mouse.py;
}

void DeviceMouseInput::GetMouseScreenSpaceCursorPosition(int* x, int* y)
{
	POINT lPoint;
	GetCursorPos(&lPoint);

	*x = lPoint.x;
	*y = lPoint.y;

	_mouse.px = (float)(*x);
	_mouse.py = (float)(*y);

	if (_mouse.px < _mouse.clip.left)
		_mouse.px = (float)_mouse.clip.left;
	else if (_mouse.px > _mouse.clip.right)
		_mouse.px = (float)_mouse.clip.right;

	if (_mouse.py < _mouse.clip.top)
		_mouse.py = (float)_mouse.clip.top;
	else if (_mouse.py > _mouse.clip.bottom)
		_mouse.py = (float)_mouse.clip.bottom;
}